﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading;
using Turquoise.Business.Abstract;
using Turquoise.Business.Options;
using Turquoise.Core.Entities;
using Turquoise.DataAccess.Abstract;
using Turquoise.Entities.Complex.UserModels;
using Turquoise.Entities.Data;
using Turquoise.Exceptions;
using Turquoise.Globalization;
using Turquoise.Helpers;
using Turquoise.Validation.FluentValidation.UserValidation;

namespace Turquoise.Business
{
    public class SessionManager : ISessionService
    {
        private readonly ILanguageService _languageService;
        private readonly IRepository<User> _repositoryUser;
        private readonly IRepository<Session> _repositorySession;
        private readonly IRepository<SessionHistory> _repositorySessionHistory;

        public SessionManager(ILanguageService languageService, IRepository<Session> repositorySession, IRepository<User> repositoryUser, IRepository<SessionHistory> repositorySessionHistory)
        {
            _languageService = languageService;
            _repositorySession = repositorySession;
            _repositoryUser = repositoryUser;
            _repositorySessionHistory = repositorySessionHistory;
        }

        public LoginModel Login()
        {
            var loginModel = new LoginModel
            {
                Languages = _languageService.GetAll()
            };
            var identity = (TurquoiseIdentity)Thread.CurrentPrincipal.Identity;
            if (!identity.RememberMe)
            {
                return loginModel;
            }
            loginModel.Username = identity.Username;
            loginModel.Password = identity.Password;
            loginModel.RememberMe = identity.RememberMe;
            return loginModel;

        }

        public void Login(LoginModel model)
        {
            var validator = new LoginValidator(model);
            model.User = new User
            {
                Username = model.Username,
                Password = model.Password
            };

            var validationResults = validator.Validate();
            if (!validator.IsValid)
            {
                throw new ValidationException(Resources.InvalidEntityMessage)
                {
                    ValidationResult = validationResults
                };
            }

            var user = _repositoryUser.Get(e=>e.Username==model.Username);

            if (user == null)
            {
                throw new NotFoundException(Resources.NotFound);
            }
            
            if (model.Password.ToSha512()!=user.Password)
            {
                throw new NotFoundException(Resources.PasswordIncorrect);
            }
            if (!user.IsApproved)
            {
                throw new NotApprovedException(Resources.ThisRecordNotApproved);
            }

            var sessionIdList= new List<int>();
            if (user.Sessions.Count > 0)
            {
                foreach (var session in user.Sessions)
                {
                    _repositorySessionHistory.Add(new SessionHistory
                    {
                        CreatedBy = session.CreatedBy,
                        CreateDate = session.CreateDate,
                        UpdateDate = DateTime.Now,
                        LogoutType = LogoutOptions.InvalidLogout.ToString()
                    });
                    sessionIdList.Add(session.Id);
                }
            }
            foreach (var i in sessionIdList)
            {
                _repositorySession.Delete(_repositorySession.Get(e=>e.Id==i));
            }

            _repositorySession.Add(new Session
            {
                CreatedBy = user.Id,
                CreateDate = DateTime.Now
            });

            if (user.UserGroupUserLines_User.Count <= 0)
            {
                throw new NotApprovedException(Resources.ThisRecordNotApproved);
            }
            var userGroups = user.UserGroupUserLines_User;
            var userRoles = new List<int>();
            foreach (var userGroup in userGroups)
            {
                userRoles.AddRange(userGroup.UserGroup.UserGroupRoleLines.Select(role => role.RoleId));
            }
            var identity = new TurquoiseIdentity
            {
                UserId = user.Id,
                Username = user.Username,
                Password = !model.RememberMe ? null : model.Password,
                IsAuthenticated = true,
                LanguageCode = user.Language.LanguageCode,
                RememberMe = model.RememberMe,
                Name = user.FullName,
                UserRoles = userRoles
            };
            var principal = new TurquoisePrincipal(identity);
            Thread.CurrentPrincipal = principal;
            var languageCode = _languageService.GetCodeById(user.LanguageId);

            Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(languageCode);
            Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture(languageCode);
        }

        public void Logout(LogoutOptions logoutOptions)
        {
            var identity = (TurquoiseIdentity)Thread.CurrentPrincipal.Identity;
            var sessions = _repositorySession.GetList(e=>e.CreatedBy==identity.UserId);

            if (sessions.Count > 0)
            {
                foreach (var session in sessions)
                {
                    _repositorySessionHistory.Add(new SessionHistory
                    {
                        CreatedBy = session.CreatedBy,
                        CreateDate = session.CreateDate,
                        UpdateDate = DateTime.Now,
                        LogoutType = logoutOptions.ToString()
                    });
                    _repositorySession.Delete(session);
                }
            }
            var userRoles = new List<int> { 0 };
            identity.UserId = 0;
            identity.IsAuthenticated = false;
            identity.Name = "Guest";
            identity.Username = "Guest";
            identity.RememberMe = false;
            identity.UserRoles = userRoles;
            identity.LanguageCode = Thread.CurrentThread.CurrentCulture.ToString();
            var principle = new TurquoisePrincipal(identity);
            Thread.CurrentPrincipal = principle;
        }
    }
}
